import * as Cesium from '@cesiumjs';
import createGroundRectangle from "../../../utils/createGroundRectangle"
// groundImages
/**
 * GroundImage用来创建贴地图像，并且图像可以轮换
 * @memberof Obj
 * @class
 * @extends XbsjCzmObj
 */

const $defaultOptions = {
  position: [0, 0, 0],
  width: 800,
  height: 600,
  autoWidth: false,
  autoHeight: true,
  origin: [0.5, 0.5],
  rotation: 0.0,
  textureWidth: 1024,
  textureHeight: 1024,
  show: true,
  // ground: true,
  urls: [], // imageUrls
  timeDuration: 1000, // 单位秒
  currentTime: 1,
  loopPlay: true,
  times: [],
  opacity: .50
};

var whiteImageBuffer = new Uint8Array([255, 255, 255, 0]);

class GroundImages {
  constructor(viewer, options) {
    this.viewer = viewer;
    this.scene = this.viewer.scene;
    this.options = {
      ...$defaultOptions,
      ...options
    };

    this._images = [];
    this._leftImage = undefined;
    this._rightImage = undefined;
    this.initImages();
  }

  get images() {
    return this._images
  }
  set images(arr) {
    this._images = arr
    this.imageChanged()
  }
  get opacity() {
    return this.options.opacity
  }
  set opacity(val) {
    val = Math.max(val, 0)
    val = Math.min(val, 1)
    this.options.opacity = val
    this.updateOpacity()
    this.imageChanged()
  }
  get currentTime() {
    return this.options.currentTime
  }
  set currentTime(val) {
    val = Math.max(val, 0)
    val = val % this.options.timeDuration
    this.options.currentTime = val
    this.imageChanged()
  }
  get timeDuration() {
    return this.options.timeDuration
  }
  set timeDuration(val) {
    val = Math.max(val, 0)
    this.options.timeDuration = val
    this.imageChanged()
  }

  initImages() {
    this.initMaterial()
    this.updateMaterialSize()
    this.updateGroundPrimitive()
    this.updateOpacity()
    // this.addRectangleImage() //text
    this.loadImages()
  }

  imageChanged() {
    var _this = this;
    const opt = this.options
    var l = _this._images.length;
    if (l === 0) {
      _this._leftImage = undefined;
      _this._rightImage = undefined;

      _this._material.materials.left.uniforms.image.copyFrom({
        width: 1,
        height: 1,
        arrayBufferView: whiteImageBuffer
      });
      _this._material.materials.left.uniforms.stscale = new Cesium.Cartesian2(1 / opt.textureWidth, 1 /
        opt.textureHeight);

      _this._material.materials.right.uniforms.image.copyFrom({
        width: 1,
        height: 1,
        arrayBufferView: whiteImageBuffer
      });
      _this._material.materials.right.uniforms.stscale = new Cesium.Cartesian2(1 / opt.textureWidth, 1 /
        opt.textureHeight);

      return;
    }

    var currentTime = _this.currentTime > opt.timeDuration ? 0.0 : _this.currentTime;

    var index = 0;
    var intervalT = 0;

    // 等间距的操作模式
    if (l >= 2) {
      if (!opt.times || opt.times.length === 0) {
        var interval = opt.timeDuration / (l - 1);
        var pos = currentTime / interval;
        index = Math.floor(pos);
        intervalT = pos - index;
      } else {
        index = opt.times.findIndex(function(time) {
          return time > currentTime;
        }) - 1;
        if (index < 0) {
          index = 0;
          intervalT = 0;
        } else if (index >= _this._images.length - 1) {
          index = _this._images.length - 2;
          intervalT = 1.0;
        } else {
          intervalT = (currentTime - opt.times[index]) / (opt.times[index + 1] - opt.times[index]);
        }
      }
    }

    if (_this._leftImage !== _this._images[index]) {
      _this._leftImage = _this._images[index];
      var image = _this._leftImage;
      let uniforms$image = _this._material.materials.left.uniforms.image;
      uniforms$image.copyFrom({
        source: image
      });
      _this._material.materials.left.uniforms.stscale = new Cesium.Cartesian2(image.width / opt
        .textureWidth, image.height / opt.textureHeight);
    }

    if (l >= 2 && _this._rightImage !== _this._images[index + 1]) {
      _this._rightImage = _this._images[index + 1];
      var _image = _this._rightImage;
      _this._material.materials.right.uniforms.image.copyFrom({
        source: _image
      });
      _this._material.materials.right.uniforms.stscale =
        new Cesium.Cartesian2(_image.width / opt.textureWidth, _image.height / opt.textureHeight);
    }

    _this._material.uniforms.t = intervalT;
  }

  loadImages() {
    var _this = this;
    const imageUrls = this.options.urls || [];
    var promises = imageUrls.map(e => {
      return new Promise(function(resolve, reject) {
        Cesium.Resource.fetchImage({
          url: e
        }).then(function(image) {
          resolve(image);
        });
        // 这样写也可以
        // var img = new Image();
        // img.src = e;
        // img.onload = () => {
        //     resolve(img);
        // };
      });
    })
    Promise.all(promises)
      .then((result) => {
        console.log('准备完毕');
        console.log(result);
        _this.images = result;
      })
  }
  // test
  addRectangleImage() {
    var rectangle = this.scene.primitives.add(
      new Cesium.GroundPrimitive({
        geometryInstances: new Cesium.GeometryInstance({
          geometry: new Cesium.RectangleGeometry({
            rectangle: Cesium.Rectangle.fromDegrees(80.0, 30.0, 160.0, 50.0),
            vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
          })
        }),
        appearance: new Cesium.EllipsoidSurfaceAppearance({
          aboveGround: false
        })
      })
    );
    rectangle.appearance.material = new Cesium.Material({
      fabric: {
        type: 'Image',
        uniforms: {
          image: '//zzgis.com/cdn/3d/Sandcastle/images/Cesium_Logo_Color.jpg'
        }
      }
    });
  }

  initMaterial() {
    let vm = this;
    const {
      viewer,
      scene
    } = this;

    const imageUrls = this.options.urls || [];

    const _material = new Cesium.Material({
      fabric: {
        type: 'ImageMapXC',
        materials: {
          left: {
            type: 'ScaleImageXC',
            uniforms: {
              image: Cesium.Material.DefaultImageId,
              repeat: new Cesium.Cartesian2(1.0, 1.0),
              color: new Cesium.Color(1.0, 1.0, 1.0, 1.0),
              stscale: new Cesium.Cartesian2(1.0, 1.0)
            },
            components: {
              diffuse: 'texture2D(image, fract(repeat * materialInput.st) * stscale).rgb * color.rgb',
              alpha: 'texture2D(image, fract(repeat * materialInput.st) * stscale).a * color.a'
            }
          },
          right: {
            type: 'ScaleImageXC',
            uniforms: {
              image: Cesium.Material.DefaultImageId,
              repeat: new Cesium.Cartesian2(1.0, 1.0),
              color: new Cesium.Color(1.0, 1.0, 1.0, 1.0),
              stscale: new Cesium.Cartesian2(1.0, 1.0)
            },
            components: {
              diffuse: 'texture2D(image, fract(repeat * materialInput.st) * stscale).rgb * color.rgb',
              alpha: 'texture2D(image, fract(repeat * materialInput.st) * stscale).a * color.a'
            }
          }
        },
        uniforms: {
          t: 0.0,
          opacity: 1.0
        },
        components: {
          diffuse: 'left.diffuse * (1.0 - t) + right.diffuse * t',
          alpha: '(left.alpha * (1.0 - t) + right.alpha * t) * opacity'
        }
      }
    });

    this._material = _material;
  }

  updateMaterialSize() {
    const {
      viewer,
      scene,
      options
    } = this;
    const {
      textureWidth,
      textureHeight
    } = options;

    this._leftHeatmapTexture && this._leftHeatmapTexture.destroy();

    this._leftHeatmapTexture = new Cesium.Texture({
      context: scene.context,
      width: textureWidth,
      height: textureHeight
    });

    this._rightHeatmapTexture && this._rightHeatmapTexture.destroy();

    this._rightHeatmapTexture = new Cesium.Texture({
      context: scene.context,
      width: textureWidth,
      height: textureHeight
    });

    this._material.materials.left.uniforms.image = this._leftHeatmapTexture;
    this._material.materials.right.uniforms.image = this._rightHeatmapTexture;
    // this._material.materials.left.uniforms.color = new Cesium.Color(1, 0, 0, 0.5); //test
    // this._material.materials.right.uniforms.color = new Cesium.Color(0, 0, 1, 0.5); //test
  };

  updateGroundPrimitive() {
    const _this = this;
    const {
      viewer,
      scene,
      options
    } = _this;
    _this._groundPrimitive && scene.groundPrimitives.remove(_this._groundPrimitive);
    _this._groundPrimitive = undefined;

    const {
      position,
      origin,width,height,
      textureWidth,
      textureHeight
    } = options || {};

    var ox = origin[0];
    var oy = origin[1];

    Cesium.GroundPrimitive.initializeTerrainHeights().then(() => {
      var groundImage = createGroundRectangle(position, width, height, ox, oy, _this.rotation, undefined);
      // var groundImage = createGroundRectangle(position, textureWidth);
      _this._groundPrimitive = scene.groundPrimitives.add(groundImage);
      _this._groundPrimitive.show = options.show; // 避免groundImage创建时设置show属性不起作用
      _this._groundPrimitive.appearance.material = _this._material;
    })
  };

  updateOpacity() {
    const _this = this;
    _this._material.uniforms.opacity = _this.options.opacity;
  };

  flyTo() {
    const {
      position,
      width
    } = this.options
    this.viewer.camera.flyTo(position, width, [0, -Math.PI / 3, 0]);
  }
  destroy() {
  }
};

export default GroundImages;
